package com.ict.ms.trackPlayBack.facade.common;

import com.vividsolutions.jts.geom.Coordinate;
import com.vividsolutions.jts.geom.GeometryFactory;
import com.vividsolutions.jts.geom.Point;
import com.vividsolutions.jts.geom.Polygon;
import org.geotools.geometry.jts.JTSFactoryFinder;

import java.util.ArrayList;
import java.util.List;

public class PolygonWithLongitudeCrossed180 {
    private static GeometryFactory geometryFactory = JTSFactoryFinder.getGeometryFactory( null );
    private Polygon polygon = null;
    private Boolean is180LongitudeCrossed = false;

    public PolygonWithLongitudeCrossed180(ArrayList<Double> LongtitudeList, ArrayList<Double> LatitudeList){
        if(LongtitudeList.size() != LatitudeList.size()){
            System.out.println("LongtitudeList size not equal LatitudeList size");
             throw new IllegalArgumentException("LongtitudeList size not equal LatitudeList size");
        }
        List<Coordinate> points=new ArrayList<Coordinate>();
        for (int i = 0; i < LatitudeList.size() ; i++) {
            Coordinate temp_point = createPoint(LongtitudeList.get(i), LatitudeList.get(i));
            points.add(temp_point);
        }
        boolean isValid = setIs180LongitudeCrossedAndCheckPointsValidity(points);
        if(!isValid){
             throw new IllegalArgumentException("Invalid points in polygon points list");
        }
        if(is180LongitudeCrossed){
            points = translatePointsWhenNeeded(points);
        }
        polygon= PolygonWithLongitudeCrossed180.createPolygon(points);
    }


    /**
     * create a Point
     * @param x
     * @param y
     * @return
     */
    private Coordinate createPoint(double x,double y){
        return new Coordinate(x,y);
    }
    /**
     * create a point
     * @return Geometry
     */
    private Point createGeoPoint(double x,double y){
        Coordinate coord = new Coordinate(x, y);
        Point point = geometryFactory.createPoint( coord );
        return point;
    }

    /**
     * 根据点串创建多边形
     * @param points
     * @return
     */
    private static Polygon createPolygon(List<Coordinate> points){
        Coordinate[] coords  = (Coordinate[]) points.toArray(new Coordinate[points.size()]);
        return geometryFactory.createPolygon(coords);
    }




    private List<Coordinate> translatePointsWhenNeeded(List<Coordinate> PolygonList){
        for(Integer i = 0;i < PolygonList.size(); i++){
            Coordinate temp = PolygonList.get(i);
            if(temp.x < 0){
                temp.x += 360;
                PolygonList.set(i,temp);
            }
        }
        return PolygonList;
    }

    private boolean checkPointFValidity(Coordinate p){
        if(p.x<-180||p.x>180||p.y>90||p.y<-90)
        {
            System.out.println(String.format("Invalid points:<%f,%f>",p.x,p.y));
            return false;
        }
        return true;
    }

    private boolean setIs180LongitudeCrossedAndCheckPointsValidity(List<Coordinate> PolygonList){
        Coordinate lastPointF = null;
        boolean isLastPointValid=false;
        for(Integer i = 0;i < PolygonList.size(); i++) {
            if (!isLastPointValid) {
                lastPointF = PolygonList.get(i);
                if (!checkPointFValidity(lastPointF)) {
                    return false;
                }
                isLastPointValid = true;
            } else {
                Coordinate currentPoint = PolygonList.get(i);
                if (!checkPointFValidity(currentPoint)) {
                    return false;
                }
                if (currentPoint.x * lastPointF.x < 0) //one positive longitude, one negative longitude
                {
                    if (Math.abs(currentPoint.x - lastPointF.x) > 180) //180 degree crossed
                    {
                        is180LongitudeCrossed= true;
                    }
                }
                lastPointF = currentPoint;
            }
        }
        return true;
    }

    public Boolean containsPoint(double x,double y)
    {
        if(!checkPointFValidity(createPoint(x,y))){
            throw new IllegalArgumentException(String.format("Invalid points:<%f,%f>",x,y));
        }

        if(x<0&&is180LongitudeCrossed)
            x = x+360;

        Point point=createGeoPoint(x,y);
        return polygon.contains(point);
    }


}